using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using Decav.Gatsb.Application;

namespace Decav.Gatsb.Web.Controls
{
    /// <summary>
    /// Renders a <see cref="Post"/> or its summary into a web control.
    /// </summary>
    public class PostRenderer
    {
        /// <summary>
        /// Initializes a new <see cref="PostRenderer"/> instance.
        /// </summary>
        /// <param name="writer">The writer the renderer will output to.</param>
        /// <param name="wrappingTag">The type of tag that will wrap the contents output by the renderer.</param>
        public PostRenderer(HtmlTextWriter writer, HtmlTextWriterTag wrappingTag)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");

            _writer = writer;
            _wrappingTag = wrappingTag;
        }

        private HtmlTextWriter _writer;
        private Post _post;
        private HtmlTextWriterTag _wrappingTag;
        private bool _includePlaceName;
        private NameFormat _nameFormat = NameFormat.FullName;

        /// <summary>
        /// Gets whether or not the post has images.
        /// </summary>
        private bool PostHasPictures
        {
            get
            {
                return _post.Attachments.Count > 0;
            }
        }

        /// <summary>
        /// Gets or sets whether the name of the place the item was taken should be included.
        /// </summary>
        public bool IncludePlaceName
        {
            get
            {
                return _includePlaceName;
            }
            set
            {
                _includePlaceName = value;
            }
        }

        /// <summary>
        /// Gets or sets how the peoples names should be rendered.
        /// </summary>
        public NameFormat NameFormat
        {
            get
            {
                return _nameFormat;
            }
            set
            {
                _nameFormat = value;
            }
        }

        /// <summary>
        /// Renders the <paramref name="post"/> to the writer output.
        /// </summary>
        /// <param name="post">The post to render.</param>
        public void RenderSummary(Post post)
        {
            if (post == null)
                throw new ArgumentNullException("post");

            _post = post;
            _writer.RenderBeginTag(_wrappingTag);

            RenderHeader();

            _writer.AddAttribute(HtmlTextWriterAttribute.Class, "PostBody");
            _writer.RenderBeginTag(HtmlTextWriterTag.Div);
            RenderBody();
            RenderAttachments();
            _writer.RenderEndTag(); // div

            RenderMenu();

            RenderClearDiv();
            _writer.RenderEndTag(); // wrappingTag

            _post = null;
        }

        private void RenderMenu()
        {
            _writer.AddAttribute(HtmlTextWriterAttribute.Class, "PostMenu");
            _writer.RenderBeginTag(HtmlTextWriterTag.Ul);

            
            _writer.RenderBeginTag(HtmlTextWriterTag.Li);
            _writer.AddAttribute(HtmlTextWriterAttribute.Href, string.Format("Post.aspx?id={0}", _post.Id));
            _writer.RenderBeginTag(HtmlTextWriterTag.A);
            _writer.Write("View");
            _writer.RenderEndTag(); // A
            _writer.RenderEndTag(); // Li


            _writer.RenderEndTag(); // Ul
        }

        private void RenderClearDiv()
        {
            _writer.AddAttribute(HtmlTextWriterAttribute.Class, "ClearingDiv");
            _writer.RenderBeginTag(HtmlTextWriterTag.Div);
            _writer.RenderEndTag();
        }

        private void RenderHeader()
        {
            string type = "a note";
            if (_post.Attachments.Count == 1)
                type = "a picture";
            else if (_post.Attachments.Count > 1)
                type = "some pictures";

            _writer.AddAttribute(HtmlTextWriterAttribute.Class, "PostMetadata");
            _writer.RenderBeginTag(HtmlTextWriterTag.Div);
            RenderPersonName(_writer, _post.Owner, _nameFormat);
            _writer.Write(" posted {0}", type);

            if (IncludePlaceName)
            {
                _writer.Write(" at ");
                RenderLocationName(_writer, _post.Location);
            }

            _writer.Write(" {0}:", StringFormatting.ToTimeAgo(_post.CreateDate));

            _writer.RenderEndTag();
        }

        private void RenderBody()
        {
            // Ignore an empty body.
            if (_post.Body == null || _post.Body.Trim().Length == 0)
                return;

            _writer.RenderBeginTag(HtmlTextWriterTag.P);
            _writer.Write(_post.Body.Trim());
            _writer.RenderEndTag(); // P  
        }

        private void RenderAttachments()
        {
            if (_post.Attachments.Count == 0)
                return;

            _writer.AddAttribute(HtmlTextWriterAttribute.Class, "PostAttachments");
            _writer.RenderBeginTag(HtmlTextWriterTag.Ul);
            foreach (PostAttachment attachment in _post.Attachments)
            {
                _writer.RenderBeginTag(HtmlTextWriterTag.Li);

                _writer.AddAttribute(HtmlTextWriterAttribute.Href, string.Format("Post.aspx?id={0}", _post.Id));
                _writer.RenderBeginTag(HtmlTextWriterTag.A);

                _writer.AddAttribute(HtmlTextWriterAttribute.Src, GatsbApplication.Current.GetImageUrl(attachment.Id, UserImageSize.Thumbnail));
                _writer.AddAttribute(HtmlTextWriterAttribute.Alt, string.Empty);
                _writer.RenderBeginTag(HtmlTextWriterTag.Img);
                _writer.RenderEndTag(); // img

                _writer.RenderEndTag(); // A

                _writer.RenderEndTag(); //li
            }
            _writer.RenderEndTag(); //ul
        }

        public static void RenderPersonName(HtmlTextWriter writer, User person, NameFormat format)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");

            if (person == null)
                throw new ArgumentNullException("person");

            writer.AddAttribute(HtmlTextWriterAttribute.Href, string.Format("Person.aspx?id={0}", person.Id));
            writer.RenderBeginTag(HtmlTextWriterTag.A);

            if (format == NameFormat.FirstName)
                writer.Write(person.Name.FirstName);
            else
                writer.Write(person.Name.ToString());

            writer.RenderEndTag(); // a
        }

        public static void RenderLocationName(HtmlTextWriter writer, Location location)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");
        

            if (location == null)
            {
                writer.Write("an undefined location");
            }
            else
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Href, string.Format("Place.aspx?id={0}", location.Id));
                writer.RenderBeginTag(HtmlTextWriterTag.A);
                writer.Write(location.Name);
                writer.RenderEndTag(); // A
            }
        }
    }

    /// <summary>
    /// Enumerates the formats that names can be presented in.
    /// </summary>
    public enum NameFormat
    {
        /// <summary>
        /// Specifies only the first name for render.
        /// </summary>
        FirstName,

        /// <summary>
        /// Specifies the full name for render.
        /// </summary>
        FullName
    }
}
